﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Telerik.Windows.Controls;
using System.Collections.Specialized;
using System.Collections;
using System.Windows.Data;
using ExORMDesginer.UserControls.CCodeEditer;
using System.Collections.ObjectModel;
using ExORMDesginer.Models;

namespace ExORMDesginer.Helper
{
	public class PaneGroupExtensions
	{
		private RadPaneGroup Group { get; set; }

		private Dictionary<object, RadPane> Panes { get; set; }

		private PaneGroupExtensions()
		{
			this.Panes = new Dictionary<object, RadPane>();
		}

		private void RemoveItem(object paneModel)
		{
			if (this.Panes.ContainsKey(paneModel))
			{
				var pane = this.Panes[paneModel];

				// NOTE: This code depends on the custom logic! This implementation will leave the panes that are removed from the group by the user.

				////if (this.Group.Items.Contains(pane))
				////{
				////    this.Group.Items.Remove(pane);
				////}

				// NOTE: This code depends on the custom logic! This implementation will remove all the panes no matter
				pane.RemoveFromParent();

				this.Panes.Remove(paneModel);
                var items = GetItemsSource(this.Group) as ObservableCollection<SQLEditerItemInfo>;
                items.Remove((SQLEditerItemInfo)paneModel);
			}
		}

		private void AddItem(object paneModel)
		{
			this.InsertItem(this.Panes.Count, paneModel);
		}

		private void InsertItem(int index, object paneModel)
		{
			if (this.Panes.ContainsKey(paneModel))
				return;




            CCodeEditer editer = new CCodeEditer(EditerType.SQL);
		    dynamic obj = paneModel;
		    obj.View = editer;
            editer.DataContext = paneModel;
            Binding binding = new Binding();
            binding.Source = paneModel;
            binding.Path = new PropertyPath("SQL");
            binding.Mode = BindingMode.TwoWay;
            binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            editer.SetBinding(CCodeEditer.TextProperty, binding);

            Binding binding1 = new Binding();
            binding1.Source = paneModel;
            binding1.Path = new PropertyPath("SQL");
            binding1.Mode = BindingMode.OneTime;
            editer.SetBinding(CCodeEditer.InitTextProperty, binding1);
			var pane = new RadPane
			{
				// TODO: Set what needed;
				DataContext = paneModel,
				Header = paneModel,
                Content = editer,
				HeaderTemplate = GetItemHeaderTemplate(this.Group),
				TitleTemplate = GetItemTitleTemplate(this.Group),
                ContentTemplate = GetItemContentTemplate(this.Group)
			};
            pane.ContextMenuTemplate = null;
            pane.IsPinned = true;


			var titleDisplayMemberPath = GetItemTitleDisplayMemberPath(this.Group) as string;
			if (!string.IsNullOrEmpty(titleDisplayMemberPath))
				pane.SetBinding(RadPane.TitleProperty, new Binding(titleDisplayMemberPath) { Source = paneModel });

			this.Panes.Add(paneModel, pane);

			this.Group.Items.Insert(index, pane);
		}

		public static DataTemplate GetItemHeaderTemplate(DependencyObject obj)
		{
			return (DataTemplate)obj.GetValue(ItemHeaderTemplateProperty);
		}

		public static void SetItemHeaderTemplate(DependencyObject obj, DataTemplate value)
		{
			obj.SetValue(ItemHeaderTemplateProperty, value);
		}

		public static readonly DependencyProperty ItemHeaderTemplateProperty =
			DependencyProperty.RegisterAttached("ItemHeaderTemplate", typeof(DataTemplate), typeof(PaneGroupExtensions), new PropertyMetadata(OnItemHeaderTemplateChanged));

		private static void OnItemHeaderTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var group = d as RadPaneGroup;
			var oldValue = e.OldValue as DataTemplate;
			var newValue = e.NewValue as DataTemplate;
			if (group != null)
			{
				var extension = GetPaneGroupExtension(group);

				if (extension == null)
					return;

				foreach (var pane in extension.Panes.Values)
				{
					pane.SetValue(RadPane.HeaderTemplateProperty, newValue);
				}
			}
		}

		public static DataTemplate GetItemTitleTemplate(DependencyObject obj)
		{
			return (DataTemplate)obj.GetValue(ItemTitleTemplateProperty);
		}

		public static void SetItemTitleTemplate(DependencyObject obj, DataTemplate value)
		{
			obj.SetValue(ItemTitleTemplateProperty, value);
		}

		public static readonly DependencyProperty ItemTitleTemplateProperty =
			DependencyProperty.RegisterAttached("ItemTitleTemplate", typeof(DataTemplate), typeof(PaneGroupExtensions), new PropertyMetadata(OnItemTitleTemplateChanged));

		private static void OnItemTitleTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var group = d as RadPaneGroup;
			var oldValue = e.OldValue as DataTemplate;
			var newValue = e.NewValue as DataTemplate;
			if (group != null)
			{
				var extension = GetPaneGroupExtension(group);

				if (extension == null)
					return;

				foreach (var pane in extension.Panes.Values)
				{
					pane.SetValue(RadPane.TitleTemplateProperty, newValue);
				}
			}
		}

		public static string GetItemTitleDisplayMemberPath(DependencyObject obj)
		{
			return (string)obj.GetValue(ItemTitleDisplayMemberPathProperty);
		}

		public static void SetItemTitleDisplayMemberPath(DependencyObject obj, string value)
		{
			obj.SetValue(ItemTitleDisplayMemberPathProperty, value);
		}

		public static readonly DependencyProperty ItemTitleDisplayMemberPathProperty =
			DependencyProperty.RegisterAttached("ItemTitleDisplayMemberPath", typeof(string), typeof(PaneGroupExtensions), new PropertyMetadata("", OnItemTitleDisplayMemberPathChanged));

		private static void OnItemTitleDisplayMemberPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var group = d as RadPaneGroup;
			var oldValue = e.OldValue as string;
			var newValue = e.NewValue as string;
			if (group != null)
			{
				var extension = GetPaneGroupExtension(group);

				if (extension == null)
					return;

				if (string.IsNullOrEmpty(newValue))
				{
					foreach (var pane in extension.Panes.Values)
						pane.ClearValue(RadPane.TitleProperty);
				}

				foreach (var paneModel in extension.Panes)
				{
					// TODO: Update the binding of the Title.
					extension.Panes[paneModel].SetBinding(RadPane.TitleProperty, new Binding(newValue) { Source = paneModel });
				}
			}
		}

		public static DataTemplate GetItemContentTemplate(DependencyObject obj)
		{
			return (DataTemplate)obj.GetValue(ItemContentTemplateProperty);
		}

		public static void SetItemContentTemplate(DependencyObject obj, DataTemplate value)
		{
			obj.SetValue(ItemContentTemplateProperty, value);
		}

		public static readonly DependencyProperty ItemContentTemplateProperty =
			DependencyProperty.RegisterAttached("ItemContentTemplate", typeof(DataTemplate), typeof(PaneGroupExtensions), new PropertyMetadata(OnItemContentTemplateChanged));

		private static void OnItemContentTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var group = d as RadPaneGroup;
			var oldValue = e.OldValue as DataTemplate;
			var newValue = e.NewValue as DataTemplate;
			if (group != null)
			{
				var extension = GetPaneGroupExtension(group);

				if (extension == null)
					return;

				foreach (var pane in extension.Panes.Values)
				{
					pane.SetValue(RadPane.ContentTemplateProperty, newValue);
				}
			}
		}

		private static PaneGroupExtensions GetPaneGroupExtension(DependencyObject obj)
		{
			return (PaneGroupExtensions)obj.GetValue(PaneGroupExtensionProperty);
		}

		private static void SetPaneGroupExtension(DependencyObject obj, PaneGroupExtensions value)
		{
			obj.SetValue(PaneGroupExtensionProperty, value);
		}

		private static readonly DependencyProperty PaneGroupExtensionProperty =
			DependencyProperty.RegisterAttached("PaneGroupExtension", typeof(PaneGroupExtensions), typeof(PaneGroupExtensions), null);

		public static IEnumerable GetItemsSource(DependencyObject obj)
		{
			return (IEnumerable)obj.GetValue(ItemsSourceProperty);
		}

		public static void SetItemsSource(DependencyObject obj, IEnumerable<RadPane> value)
		{
			obj.SetValue(ItemsSourceProperty, value);
		}

		public static readonly DependencyProperty ItemsSourceProperty =
			DependencyProperty.RegisterAttached("ItemsSource", typeof(IEnumerable), typeof(PaneGroupExtensions), new PropertyMetadata(null, OnItemsSourceChanged));

		private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			var group = d as RadPaneGroup;

            var docking = group.GetVisualParent<RadDocking>();
            docking.PreviewClose += new EventHandler<Telerik.Windows.Controls.Docking.StateChangeEventArgs>(docking_PreviewClose);
			var oldValue = e.OldValue as IEnumerable;
			var newValue = e.NewValue as IEnumerable;
			var oldValueObservableCollection = e.OldValue as INotifyCollectionChanged;
			var newValueObservableCollection = e.NewValue as INotifyCollectionChanged;

			if (group != null)
			{
				var extension = GetPaneGroupExtension(group);

				if (extension == null)
				{
					extension = new PaneGroupExtensions { Group = group };
					SetPaneGroupExtension(group, extension);
				}

				if (oldValue != null)
				{
					foreach (var paneModel in oldValue)
					{
						extension.RemoveItem(paneModel);
					}

					if (oldValueObservableCollection != null)
					{
						oldValueObservableCollection.CollectionChanged -= extension.OnItemsSourceCollectionChanged;
					}
				}

				if (newValue != null)
				{
					foreach (var paneModel in newValue)
					{
						extension.AddItem(paneModel);
					}

					if (newValueObservableCollection != null)
					{
						newValueObservableCollection.CollectionChanged += extension.OnItemsSourceCollectionChanged;
					}
				}
			}
		}

        static void docking_PreviewClose(object sender, Telerik.Windows.Controls.Docking.StateChangeEventArgs e)
        {
            var docking = sender as RadDocking;
            if (docking != null)
            {
                var group = docking.ChildrenOfType<RadPaneGroup>().Where(g => g.Name == "radDock").FirstOrDefault();

                if (group != null)
                {
                    var extension = GetPaneGroupExtension(group);
           
                    var dd = e.Panes.ToList()[0];
                    var item = dd.DataContext;
                    extension.RemoveItem(item);
                    e.Handled = false;
                }
            }



        }


		private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			// TODO: Make better implementation of this.
			if (e.Action == NotifyCollectionChangedAction.Reset)
			{
				this.ClearItems();
				foreach (var paneModel in GetItemsSource(this.Group))
				{
					this.AddItem(paneModel);
				}
			}
			else
			{
				if (e.OldItems != null)
				{
					foreach (var paneModel in e.OldItems)
					{
						this.RemoveItem(paneModel);
					}
				}

				if (e.NewItems != null)
				{
					int i = Group.Items.Count;
					foreach (var paneModel in e.NewItems)
					{
						this.InsertItem(i, paneModel);
					}
				}
			}
		}

		private void ClearItems()
		{
			foreach (var pane in this.Panes.Values)
			{
				pane.RemoveFromParent();
			}

			this.Panes.Clear();
		}
	}
}
